/**
 * 实现apply方法
 * 
 */
Function.prototype.apply = function (context,args) {
  var context = context || window;// 在非严格模式下赋值给null、undefined时自动指向window
  var args = arguments[1] || [];  // 不作判断是否为数组，默认为数组
  const specialPrototype = Symbol('特殊属性Symbol') // 用于临时储存函数 避免跟上下文对象的原属性冲突的风险
  context[specialPrototype] = this;   // 给上下文新增属性，后面删除就不会改变上下文

  var result = context[specialPrototype](...args);
  delete context[specialPrototype]; //删除上下文中没有属性
  return result; // 返回结果
}



/**
 * 实现call方法
 * 
 */
Function.prototype.call = function (context) {
  // 如果没有传或传的值为空对象 context指向window
  context = context || window
  let fn = mySymbol(context)
  context[fn] = this //给context添加一个方法 指向this
  // 处理参数 去除第一个参数this 其它传入fn函数
  let arg = [...arguments].slice(1) // 获取this后面的参数
  context[fn](...arg) //执行fn
  delete context[fn] //删除方法
}




/**
 * 实现bind方法
 * 主要是要实现方法，但是不执行所以要在函数返回值
 */
Function.prototype.bind = function (context) {
  //返回一个绑定this的函数，我们需要在此保存this
  let self = this
  // 可以支持柯里化传参，保存参数
  let arg = [...arguments].slice(1)
  // 返回一个函数
  return function () {
    //同样因为支持柯里化形式传参我们需要再次获取存储参数
    let newArg = [...arguments]
    console.log(newArg)
    // 返回函数绑定this，传入两次保存的参数
    //考虑返回函数有返回值做了return
    return self.apply(context, arg.concat(newArg))
  }
}
